import logging
from django.forms.models import model_to_dict

import tsl_backend.common as common
# import tsl_backend.frontend_api.models.route as routes
import tsl_backend.frontend_api.models.order_routing as order_routing
import tsl_backend.frontend_api.models.workorder as workorders
import tsl_backend.users.models as users

import tsl_backend.fgr_api.views.fgr_apis as fgr_apis
import tsl_backend.frontend_api.serializers.serializers as frontend_serializers


def parse_worker_record(last_record_obj_by_role):
    logging.info(f"Parse worker record")

    if last_record_obj_by_role.worker:
        # check permission
        data={"worker": {
                    "actionRecord": [{
                        "action": action_record_obj.get_action_display(),
                        "time": action_record_obj.formatted_time()
                    } for action_record_obj in last_record_obj_by_role.worker.workeractionrecord_set.all()],
                    "cnName": last_record_obj_by_role.worker.account.django_user.cnName if last_record_obj_by_role.worker.account else ''
                }}
    else:
        data={"worker": {
                    "actionRecord": [],
                    "cnName": ''
                }}


    return data


def get_order_flow_record_of_flow_and_role(detail_obj, user_account_obj):
    logging.info(f"To check repeat flow occur. Get the last round the flow record start for {detail_obj}")

    user_flow = user_account_obj.department.flow

    last_order_flow_record_of_flow_and_role_obj=None
    try:
        order_routing_obj=order_routing.OrderRouting.objects.get(workorder=detail_obj)
    except Exception as e:
        logging.info("Exception of get_order_flow_record_of_flow_and_role: {e}")
        order_routing_obj=None

    if order_routing_obj:
        last_order_flow_obj=order_routing_obj.routedetail_set.filter(status__range=(2,3), flow=user_flow).order_by('seq').last()

        # Get the record according to the route detail
        if last_order_flow_obj:
            last_order_flow_record_of_flow_and_role_obj=order_routing.Record.objects.filter(route_detail=last_order_flow_obj).last()


    logging.info(f"Last order flow record for the order according to user role and flow is {last_order_flow_record_of_flow_and_role_obj}")
    return last_order_flow_record_of_flow_and_role_obj



def parse_qc_record(last_record_obj_by_role, last_record_obj, last_order_flow_record_of_flow_and_role_obj, user_account_obj, editable):
    logging.info(f"Parse QC record")
    fail_restart_flow = True if last_record_obj_by_role!=last_record_obj else False
    logging.info(f"{fail_restart_flow=}")

    if last_record_obj_by_role.qc_check:
        if fail_restart_flow:
            allow_reset = common.check_allow_qc_reset(last_record_obj_by_role, user_account_obj, last_record_obj)
            
        else:
            allow_reset=common.check_qc_record_can_reset(last_record_obj_by_role.qc_check)
            
    else:
        allow_reset=False
        
    # allow_reset, editable
    # Case 1
    # editable=True
    if editable:
        logging.info(f"User can edit the QC result. Show the QC result of last record")
        order_view_record_obj=last_record_obj

    elif not editable and allow_reset:
        # editable=False, reset=True
        logging.info(f"User cannot edit the QC result but can reset the QC result. Show the QC result of last round of flow record")
        order_view_record_obj=last_record_obj_by_role

    elif not editable and not allow_reset:
        # editable=False, reset=False
        order_view_record_obj=last_order_flow_record_of_flow_and_role_obj
        logging.info(f"User cannot edit the QC result nor reset the QC result. Show the QC result of last round of flow record according to the user flow and role")

    else:
        order_view_record_obj=None

    logging.info(f"THe order flow record to be shown is {order_view_record_obj}")

    if order_view_record_obj:
        if order_view_record_obj.qc_check:
            data={"qcCheck": {
                    "check_record_obj_pk":order_view_record_obj.qc_check.pk if order_view_record_obj.qc_check else '',
                    "failed": order_view_record_obj.qc_check.failed,
                    "remark": order_view_record_obj.qc_check.remark,
                    "fail_detail":[ {"fail_reason_id":failed_detail.reason.pk, "failed_reason":failed_detail.reason.reason, "failed_unit":failed_detail.reason.unit, "fail_qty": failed_detail.quantity} for failed_detail in order_view_record_obj.qc_check.failed_details.all() ],
                    "rec_time": order_view_record_obj.qc_check.formatted_received_at(),
                    "check_time": order_view_record_obj.qc_check.formatted_check_at(),
                    "cnName": order_view_record_obj.qc_check.account.django_user.cnName if order_view_record_obj.qc_check.account else '',
                    "allow_reset":allow_reset
                }
            }
        else:
            data={"qcCheck": {
                        "check_record_obj_pk":None,
                        "failed": None,
                        "remark": None,
                        "fail_detail":[ ],
                        "rec_time": None,
                        "check_time": None,
                        "cnName": None,
                        "allow_reset":allow_reset
                    }}
    else:
        data={"qcCheck": {
                    "check_record_obj_pk":None,
                    "failed": None,
                    "remark": None,
                    "fail_detail":[ ],
                    "rec_time": None,
                    "check_time": None,
                    "cnName": None,
                    "allow_reset":allow_reset
                }}
    
    return data


def parse_leader_record(last_record_obj_by_role, last_record_obj, last_order_flow_record_of_flow_and_role_obj, user_account_obj, editable):
    logging.info(f"Parse Leader record")
    fail_restart_flow = True if last_record_obj_by_role!=last_record_obj else False
    logging.info(f"{fail_restart_flow=}")

    if last_record_obj_by_role.leader_check:
        if fail_restart_flow:
            allow_reset = common.check_allow_qc_reset(last_record_obj_by_role, user_account_obj, last_record_obj)
            
        else:
            allow_reset=common.check_qc_record_can_reset(last_record_obj_by_role.leader_check)
            
    else:
        allow_reset=False
        
    # allow_reset, editable
    # Case 1
    # editable=True
    if editable:
        logging.info(f"User can edit the teamleader result. Show the teamleader result of last record")
        order_view_record_obj=last_record_obj

    elif not editable and allow_reset:
        # editable=False, reset=True
        logging.info(f"User cannot edit the teamleader result but can reset the teamleader result. Show the teamleader result of last round of flow record")
        order_view_record_obj=last_record_obj_by_role

    elif not editable and not allow_reset:
        # editable=False, reset=False
        order_view_record_obj=last_order_flow_record_of_flow_and_role_obj
        logging.info(f"User cannot edit the teamleader result nor reset the teamleader result. Show the teamleader result of last round of flow record according to the user flow and role")

    else:
        order_view_record_obj=None

    logging.info(f"THe order flow record to be shown is {order_view_record_obj}")

    if order_view_record_obj:
        if order_view_record_obj.leader_check:
            data={"leaderCheck": {
                    "check_record_obj_pk":order_view_record_obj.leader_check.pk if order_view_record_obj.leader_check else '',
                    "failed": order_view_record_obj.leader_check.failed,
                    "remark": order_view_record_obj.leader_check.remark,
                    "fail_detail":[ {"fail_reason_id":failed_detail.reason.pk, "failed_reason":failed_detail.reason.reason, "failed_unit":failed_detail.reason.unit, "fail_qty": failed_detail.quantity} for failed_detail in order_view_record_obj.leader_check.failed_details.all() ],
                    "rec_time": order_view_record_obj.leader_check.formatted_received_at(),
                    "check_time": order_view_record_obj.leader_check.formatted_check_at(),
                    "cnName": order_view_record_obj.leader_check.account.django_user.cnName if order_view_record_obj.leader_check.account else '',
                    "allow_reset":allow_reset
                }}
                
        else:
            data={"leaderCheck": {
                    "check_record_obj_pk":None,
                    "failed": None,
                    "remark": None,
                    "fail_detail":[ ],
                    "rec_time": None,
                    "check_time": None,
                    "cnName": None,
                    "allow_reset":allow_reset
                }}
            
    else:
        data={"leaderCheck": {
                "check_record_obj_pk":None,
                "failed": None,
                "remark": None,
                "fail_detail":[ ],
                "rec_time": None,
                "check_time": None,
                "cnName": None,
                "allow_reset":allow_reset
            }}
    
    
    
    return data



def parse_stone_record(last_record_obj_by_role, last_record_obj, last_order_flow_record_of_flow_and_role_obj, user_account_obj, editable):
    logging.info(f"Parse StoneQC record")
    fail_restart_flow = True if last_record_obj_by_role!=last_record_obj else False
    logging.info(f"{fail_restart_flow=}")

    if last_record_obj_by_role.stone_check:
        if fail_restart_flow:
            allow_reset = common.check_allow_qc_reset(last_record_obj_by_role, user_account_obj, last_record_obj)
            
        else:
            allow_reset=common.check_qc_record_can_reset(last_record_obj_by_role.stone_check)
            
    else:
        logging.info(f"No related stone_check record. Set allow reset to False as no need to reset")
        allow_reset=False
        
    # allow_reset, editable
    # Case 1
    # editable=True
    if editable:
        logging.info(f"User can edit the teamleader result. Show the teamleader result of last record")
        order_view_record_obj=last_record_obj

    elif not editable and allow_reset:
        # editable=False, reset=True
        logging.info(f"User cannot edit the teamleader result but can reset the teamleader result. Show the teamleader result of last round of flow record")
        order_view_record_obj=last_record_obj_by_role

    elif not editable and not allow_reset:
        # editable=False, reset=False
        order_view_record_obj=last_order_flow_record_of_flow_and_role_obj
        logging.info(f"User cannot edit the teamleader result nor reset the teamleader result. Show the teamleader result of last round of flow record according to the user flow and role")

    else:
        order_view_record_obj=None

    logging.info(f"THe order flow record to be shown is {order_view_record_obj}")

    if order_view_record_obj:

        if order_view_record_obj.stone_check:
            data={"stoneCheck": {
                        "check_record_obj_pk":order_view_record_obj.stone_check.pk if order_view_record_obj.stone_check else '',
                        "failed": order_view_record_obj.stone_check.failed,
                        "remark": order_view_record_obj.stone_check.remark,
                        "fail_detail":[ {"fail_reason_id":failed_detail.reason.pk, "failed_reason":failed_detail.reason.reason, "failed_unit":failed_detail.reason.unit, "fail_qty": failed_detail.quantity} for failed_detail in order_view_record_obj.stone_check.failed_details.all() ],
                        "rec_time": order_view_record_obj.stone_check.formatted_received_at(),
                        "check_time": order_view_record_obj.stone_check.formatted_check_at(),
                        "cnName": order_view_record_obj.stone_check.account.django_user.cnName if order_view_record_obj.stone_check.account else '',
                        "allow_reset":allow_reset
                    }
                }
        else:
            data={"stoneCheck": {
                "check_record_obj_pk":None,
                "failed": None,
                "remark": None,
                "fail_detail":[ ],
                "rec_time": None,
                "check_time": None,
                "cnName": None,
                "allow_reset":allow_reset
            }}
                
    else:
        data={"stoneCheck": {
            "check_record_obj_pk":None,
            "failed": None,
            "remark": None,
            "fail_detail":[ ],
            "rec_time": None,
            "check_time": None,
            "cnName": None,
            "allow_reset":allow_reset
        }}
    
    return data


def parse_orderview_data(detail_obj, user_account_obj):
    logging.info(f"Parse order view record for {detail_obj}")

    data={}

    # get the lastest order flow record that worker started already. May have one more empty flow record
    logging.info(f"Get latest order flow record that already start the flow")
    last_record_obj_by_role=common.get_latest_order_flow_record_by_role(detail_obj, user_account_obj)
    logging.info(f"The latest order flow record that already start the flow is {last_record_obj_by_role}")

    # get the last order flow record. Worker may not start the flow
    logging.info(f"Get latest order flow record ")
    last_record_obj = common.get_last_order_flow_record(detail_obj)
    logging.info(f"The latest order flow record is {last_record_obj}")

    logging.info(f"The latest order flow record according to user account flow")
    last_order_flow_record_of_flow_and_role_obj = get_order_flow_record_of_flow_and_role(detail_obj, user_account_obj)
    logging.info(f"The latest order flow record according to user account flow is {last_order_flow_record_of_flow_and_role_obj}")

    editable, error_message = common.check_user_can_change_status(
            detail_obj, last_record_obj, user_account_obj
        )
    

    if last_record_obj_by_role:
        if user_account_obj.role.name=="WORKER":
            data = parse_worker_record(last_record_obj_by_role)
        elif user_account_obj.role.name=="QC":
            data = parse_qc_record(last_record_obj_by_role, last_record_obj, last_order_flow_record_of_flow_and_role_obj, user_account_obj, editable)

        elif user_account_obj.role.name=="Teamleader":
            data = parse_leader_record(last_record_obj_by_role, last_record_obj, last_order_flow_record_of_flow_and_role_obj, user_account_obj, editable)

        elif user_account_obj.role.name=="StoneQC":
            data = parse_stone_record(last_record_obj_by_role, last_record_obj, last_order_flow_record_of_flow_and_role_obj, user_account_obj, editable)

        else:
            logging.info(f"Other roles {user_account_obj.role.name}, no need to check order on hold")

    return data, last_record_obj_by_role, last_record_obj

def get_actual_bom_fr_fgr(orderNo, source):
    logging.info(f"Get actual bom for order")
    message, instances=fgr_apis.queryActualBom(orderNo, source)
    actualbom_data = frontend_serializers.ActualbomSerializer(
                instance=instances, many=True
            ).data
    return message, actualbom_data

def set_worker_restart_flag(editable, worker_record):
    print(worker_record)
    if 'worker' in worker_record:
        if editable and worker_record["worker"]["actionRecord"]:
            if worker_record["worker"]["actionRecord"][-1]["action"]=="Complete":
                worker_record["worker"]["actionRecord"].append({
                    "action": "Restart",
                    "time": "2000.01.01 00:00:00"
                })
    
    return worker_record

def parse_stoneImgs(order):
    logging.info(f"Parse Stone Images")
    content_type='application/x-www-form-urlencoded'
    stoneImgs_res = fgr_apis.queryStoneImgs(order, content_type)
    code = stoneImgs_res["code"]

    if code == "200":
        try:
            stoneImgs = stoneImgs_res["data"]
            logging.info(f"stoneImgs: {stoneImgs}")
        except Exception as e:
            logging.error(f"Fail to get 'Imgs' from 'data': {e}")
    else:
        stoneImgs = []
        logging.warn(f"Fail to get stoneImgs [{code}]: {stoneImgs_res['message']}")

    return stoneImgs

def parse_colorImgs(order):
    logging.info(f"Parse Color Images for {order}")
    content_type='application/x-www-form-urlencoded'
    colorImgs_res = fgr_apis.queryColorImgs(order, content_type)
    code = colorImgs_res["code"]
    if code == "200":
        try:
            colorImgs = colorImgs_res["data"]
            logging.info(f"colorImgs: {colorImgs}")
        except Exception as e:
            logging.error(f"Fail to get 'imgData' from 'data': {e}")
    else:
        colorImgs = []
        logging.warn(f"Fail to get colorImgs [{code}]: {colorImgs_res['message']}")
    
    return colorImgs

def parse_orderview_status(last_order_flow_record_obj, workorder):

    data={"flow":None, "worker_name": None, "worker_record_time":None, "holder_name":None, "holder_record_time":None, "order_status":workorder.get_state_display()}
    
    logging.debug(f"parse_orderview_status: {last_order_flow_record_obj} {workorder})")
    if last_order_flow_record_obj:
        data["flow"] =last_order_flow_record_obj.route_detail.flow.chinese_name
        if last_order_flow_record_obj.worker:
            data["worker_name"] =last_order_flow_record_obj.worker.account.django_user.cnName if last_order_flow_record_obj.worker.account else None
            data["worker_record_time"]=last_order_flow_record_obj.worker.workeractionrecord_set.filter(action=1).first().formatted_time() if last_order_flow_record_obj.worker.workeractionrecord_set.filter(action=1).first() else None
        else:
            data["worker_name"] =None
            data["worker_record_time"] =None
        
        try:
            order_route_obj=workorder.orderrouting
            data["holder_name"]=order_route_obj.holder.django_user.cnName if order_route_obj.holder else None 
            if data["flow"] == "PF":
                data["holder_name"] = "PC"
            data["holder_record_time"]=order_route_obj.formatted_holder_record_time()
        except Exception as e:
            logging.warn(f"No order routing for order {workorder}")

    return data


def parse_display_config(role, user_account_obj):
    
    display_config = users.RolePermission.objects.filter(
        role=role, flow=user_account_obj.department.flow
    ).first()

    if display_config:
        display_config_dict = model_to_dict(display_config)
        display_config_data = display_config_dict
    else:
        display_config_data = {
        "show_Order_Number": True,
        "show_Due_Date": True,
        "show_Quantity": True,
        "show_Cargo_type": True,
        "show_Description": True,
        "show_Product_Size": True,
        "show_Fineness": True,
        "show_Purchases_Unit": True,
        "show_Stone_Date": True,
        "show_Flower_Patten": True,
        "show_Manifest_Type": True,
        "show_Design_Number": True,
        "show_Model_Number": True,
        "show_Black_And_White_Photo": True,
        "show_Production_Instructions": True,
        "show_Result": True,
        "show_Company_Engraving_Content": True,
        "show_Company_Engraving_Font": True,
        "show_Customer_Engraving_Content": True,
        "show_Customer_Engraving_Font": True,
        "show_Engraving_Description": True,
        "show_Engraving_Effect": True,
        "show_Ingredients": True,
        "show_Stone_Issue": True,
        "show_Stone_Detail": True,
        "show_Production_Notes": True,
        "show_Process": True,
        "show_Difficulty": True,
        "show_Divided_member": True,
        "show_Production_weight": True,
        "show_Registration_From": True,
        "show_Row_Stone_Image": True,
        "show_Colour_Image": True
    }

    return display_config_data



def update_center_sender_name(status:dict, routing: list):
    """给中央收发后添加名"""
    holder_name = status["holder_name"]
    if not holder_name:
        for index, route in enumerate(routing):
            if route["status"] in ("Open", "In Progress") :
                previous_index = index - 1
                if previous_index >= 0:
                    holder_name = routing[previous_index]["flow"] + "收发"
                break
    return holder_name